# -*- coding: UTF-8 -*-

from flask import Blueprint, request, render_template, url_for, session, flash
from sqlalchemy import or_
from werkzeug.utils import redirect

from app import db
from app.db.flow_model import WorkFlow, Node, NodeConfig, Edge, Task, Process, User, RoleMap, Role, TaskLog
from app.db.work_model import work_tables
from app.db.work_status import UserAction, ProcessStatus, TaskStatus
from app.forms import form_manage
from app.settings import id_worker

flow_blue = Blueprint("flow", __name__)


def init_flow_blue(app):
    app.register_blueprint(flow_blue, url_prefix="/flow/")


def current_user():
    if 'account' in session:
        return User.query.filter_by(account=session['account']).first()
    else:
        return None


@flow_blue.route('/', endpoint='flows')
def flows():
    user = current_user()
    roles = RoleMap.query.with_entities(RoleMap.rid).filter(RoleMap.uid == user.uid).all()
    roles = [1] + [_.rid for _ in roles]
    configs = NodeConfig.query.filter(NodeConfig.rid.in_(roles)).all()
    fids = [_.nid for _ in configs]
    user_flows = WorkFlow.query.filter(WorkFlow.fid.in_(fids)).all()
    if user.account == 'admin':
        all_flows = WorkFlow.query.all()
    else:
        all_flows = None
    return render_template("flow/flows.html", user_flows=user_flows, all_flows=all_flows)


@flow_blue.route('/flow_config/<int:fid>')
def flow_config(fid):
    user = current_user()
    flow = WorkFlow.query.filter(WorkFlow.fid == fid).first()
    users = User.query.filter_by(enabled=True).all()
    roles = Role.query.filter_by(enabled=True).all()
    # nodes=flow.nodes
    # configs =nodes.configs
    return render_template("flow/flow_config.html", **locals())


@flow_blue.route('/create_node_config/<int:nid>', methods=['GET', 'POST'])
def create_node_config(nid):
    user = current_user()
    uid = request.form.get('uid', None)
    rid = request.form.get('rid', None)
    node = Node.query.filter_by(nid=nid).first()
    exist = NodeConfig.query.filter(NodeConfig.nid == nid) \
        .filter(or_(NodeConfig.rid == rid, NodeConfig.uid == uid)).all()
    if exist:
        flash("更新成功", 'ok')
        return redirect(url_for("flow.flow_config", fid=1000))
    config = NodeConfig(nid=nid, fid=node.fid)
    if uid:
        # u=User.query.filter_by(uid=uid).first()
        config.uid = uid
    elif rid:
        config.rid = rid
    config.create_uid = user.uid
    db.session.add(config)
    db.session.commit()
    flash("添加成功", 'ok')
    return redirect(url_for("flow.flow_config", fid=1000))


@flow_blue.route('/delete_node_config/<int:id>', methods=['GET', 'POST'])
def delete_node_config(id):
    user = current_user()
    config = NodeConfig.query.filter_by(id=id).first()
    if config:
        db.session.delete(config)
        db.session.commit()
    flash("删除成功", 'ok')
    return redirect(url_for("flow.flow_config", fid=1000))


@flow_blue.route('/update_node_config_enabled/<int:id>', methods=['GET', 'POST'])
def update_node_config_enabled(id):
    user = current_user()
    config = NodeConfig.query.filter_by(id=id).first()
    if config:
        config.enabled = not config.enabled
        # 一切从简
        config.create_uid = user.uid
        db.session.add(config)
        db.session.commit()
    flash("更新成功", 'ok')
    return redirect(url_for("flow.flow_config", fid=1000))


@flow_blue.route('/flow_chart/<int:fid>', methods=['GET', 'POST'])
def flow_chart(fid):
    flow = WorkFlow.query.filter_by(fid=fid).first()
    edge_model = Edge.query.filter_by(fid=fid).all()
    node_model = Node.query.filter_by(fid=fid).all()
    nodes = []
    for node in node_model:
        nodes.append({'id': node.nid, 'label': node.name, 'title': node.doc, 'group': node.node_type})
    edges = []
    for edge in edge_model:
        edges.append(
            {'from': edge.parent_id, 'to': edge.child_id, 'id': edge.id, 'label': edge.name, 'title': edge.doc})
    return render_template("flow/flow_chart.html", flow=flow, edges=edges, nodes=nodes)


@flow_blue.route('/create_form/<int:fid>/', methods=['GET', 'POST'])
def create_form(fid):
    user = current_user()
    flow = WorkFlow.query.filter_by(fid=fid).first()

    FormClass = form_manage[flow.fid]
    form = FormClass()
    if form.validate_on_submit():

        WorkTable = work_tables[flow.work_tables]
        work_data = WorkTable()
        form.populate_obj(work_data)

        msg = ''
        try:
            task = Task(tid=id_worker.get_id(), fid=fid, uid=user.uid)
            if form.submit.data:
                task.status = TaskStatus.init
                process = Process(tid=task.tid, nid=task.fid, ppid=0, pid=1, fid=task.fid,
                                  uid=task.uid, rid=0, action=UserAction.passed
                                  )
                db.session.add(process)
                msg = "提交成功"
            elif form.save.data:
                task.status = TaskStatus.saved
                msg = "保存成功"
            work_data.tid = task.tid
            db.session.add(task)
            db.session.add(work_data)
            db.session.commit()
            flash(msg, 'ok')
            return redirect(url_for("flow.form_view", tid=task.tid))
        except Exception as e:
            db.session.rollback()
            flash("提交失败 %s" % e, 'error')
            return redirect(url_for("flow.create_form", fid=fid))

    # start_node = Node.query.filter_by(nid=fid).first()
    # form_path = start_node.form_path
    form_path = "/forms/%s.html" % flow.name
    submitter = user
    approvers = []
    current_node = Node.query.filter_by(nid=fid).first()
    return render_template(form_path, write_form=True, flow=flow, form=form, submitter=submitter,
                           process_list=None, approvers=approvers, current_node=current_node, task=None,
                           process=None, work_table=None)


@flow_blue.route('/post_form/<int:tid>/', methods=['POST'])
def post_form(tid):
    user = current_user()
    task = Task.query.filter_by(tid=tid).first()

    flow = WorkFlow.query.filter_by(fid=task.fid).first()

    FormClass = form_manage[flow.fid]
    form = FormClass()
    WorkTable = work_tables[flow.work_tables]
    work_data = WorkTable.query.filter_by(tid=tid).first()
    form.populate_obj(work_data)
    if form.validate_on_submit():
        try:
            if form.submit.data:
                task.status = TaskStatus.init
                process = Process(tid=task.tid, nid=task.fid, ppid=0, pid=1, fid=task.fid,
                                  uid=task.uid, rid=0, action=UserAction.passed
                                  )
                db.session.add(process)
            elif form.save.data:
                task.status = TaskStatus.saved
            db.session.add(task)
            db.session.add(work_data)
            db.session.commit()
            flash("提交成功", 'ok')

        except Exception as e:
            db.session.rollback()
            flash("提交失败 %s" % e, 'error')
    return redirect(url_for("flow.form_view", tid=task.tid))


@flow_blue.route('/approve_form/<string:action>/<int:id>/', methods=['GET'])
def approve_form(action, id):
    process = Process.query.filter_by(id=id).first()
    task = process.task
    if hasattr(UserAction, action) and task.status != TaskStatus.processing:
        process.action = getattr(UserAction, action)
        db.session.add(process)
        task.status = TaskStatus.init
        db.session.add(task)
        db.session.commit()
        flash("提交成功", 'ok')

    else:
        flash("提交失败", 'error')

    return redirect(url_for("flow.form_view", tid=process.tid))


@flow_blue.route('/form_view/<int:tid>/', methods=['GET', 'POST'])
def form_view(tid):
    task = Task.query.filter_by(tid=tid).first()
    submitter = User.query.filter_by(uid=task.uid).first()
    user = current_user()
    flow = WorkFlow.query.filter_by(fid=task.fid).first()

    work_table_name = flow.work_tables
    WorkTable = work_tables[work_table_name]
    work_table = WorkTable.query.filter_by(tid=task.tid).first()

    FormClass = form_manage[flow.fid]
    form = FormClass(**work_table.to_dict())
    form_path = "/forms/%s.html" % flow.name
    process_list = Process.query.filter(Process.tid == task.tid, Process.uid != 0).order_by(
        Process.create_date.asc()).all()
    approvers = [i.uid for i in process_list if i.active and i.uid != 0]

    user_process = [_ for _ in process_list if _.active and _.uid == user.uid and _.action == UserAction.init]
    process = user_process[0] if user_process else None
    current_node = process.node if process else None
    return render_template(form_path, write_form=False, task=task, flow=flow, form=form, submitter=submitter,
                           approvers=approvers, reader=user, process_list=process_list, current_node=current_node,
                           process=process, work_table=work_table)


@flow_blue.route('/process/', methods=['GET', 'POST'], endpoint='process')
def process_manage():
    user = current_user()
    draft_list = Task.query.filter_by(uid=user.uid, status=TaskStatus.saved).all()
    processing_task = Task.query.filter(Task.status == TaskStatus.processing).all()
    processing_ids = [_.tid for _ in processing_task]
    submit_list = Process.query.filter(Process.uid == user.uid, Process.nid == Process.fid,
                                       ).order_by(
        Process.pid.desc()).all()

    pending_list = Process.query.filter(Process.uid == user.uid, Process.status == ProcessStatus.init,
                                        Process.action == UserAction.init, Process.active == True).all()

    a = Process.query.with_entities((Process.tid)).filter(Process.uid == user.uid, Process.nid != Process.fid,
                                                          Process.status != ProcessStatus.init, ).distinct().all()
    b = [_[0] for _ in a]
    processed_tasks = Task.query.filter(Task.tid.in_(b)).all()
    return render_template("flow/process_manage.html", draft_list=draft_list,
                           submit_list=submit_list, processed_tasks=processed_tasks, pending_list=pending_list)


@flow_blue.route('/process/<int:fid>', methods=['GET', 'POST'])
def process_view(fid):
    flow = WorkFlow.query.filter_by(fid=fid).first()
    edge_model = Edge.query.filter_by(fid=fid).all()
    node_model = Node.query.filter_by(fid=fid).all()
    nodes = []
    for node in node_model:
        nodes.append({'id': node.nid, 'label': node.name, 'title': node.doc, 'group': node.node_type})
    edges = []
    for edge in edge_model:
        edges.append(
            {'from': edge.parent_id, 'to': edge.child_id, 'id': edge.id, 'label': edge.name, 'title': edge.doc})
    return render_template("/flow/flow_chart.html", flow=flow, edges=edges, nodes=nodes)


@flow_blue.route('/log/<int:page>/', methods=['GET'], endpoint='log')
def log_manage(page=None):
    tid = request.args.get('tid', None)
    query = TaskLog.query
    paginate_args={}
    if tid:
        query = query.filter(TaskLog.tid.like(tid))
        paginate_args['tid']=tid
    page = page if page else 10
    paginate = query.order_by(TaskLog.create_date.desc()).paginate(page=page, per_page=5)
    return render_template("/flow/log/log_manage.html", paginate=paginate, data=paginate.items,
                           paginate_args=paginate_args)


@flow_blue.route('/log/view/<int:id>/', methods=['GET'], endpoint='log_view')
def log_view(id):
    obj = TaskLog.query.filter_by(id=id).first()
    data = obj.get_data()
    return render_template("/flow/log/log_view.html", data=data)
